// ============================================
// TypeScript 函数示例
// ============================================

export {}

// 1. 基本函数定义
// 函数声明
function add(x: number, y: number): number {
    return x + y;
}

// 函数表达式
let myAdd = function(x: number, y: number): number {
    return x + y;
};

// 箭头函数
let myAdd2 = (x: number, y: number): number => x + y;

// 完整的函数类型
let myAdd3: (x: number, y: number) => number = function(x: number, y: number): number {
    return x + y;
};

console.log(add(1, 2));

// 2. 可选参数
function buildName(firstName: string, lastName?: string): string {
    if (lastName) {
        return firstName + " " + lastName;
    } else {
        return firstName;
    }
}

let result1 = buildName("Bob");
let result2 = buildName("Bob", "Adams");
// let result3 = buildName("Bob", "Adams", "Sr."); // 错误，参数过多

console.log(result1, result2);

// 3. 默认参数
function buildName2(firstName: string, lastName = "Smith"): string {
    return firstName + " " + lastName;
}

let result4 = buildName2("Bob");
let result5 = buildName2("Bob", "Adams");
let result6 = buildName2("Bob", undefined); // 使用默认值

console.log(result4, result5, result6);

// 4. 剩余参数
function buildName3(firstName: string, ...restOfName: string[]): string {
    return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName3("Joseph", "Samuel", "Lucas", "MacKinzie");
console.log(employeeName);

// 剩余参数在函数类型中的使用
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName3;

// 5. 函数重载
// 重载签名
function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
// 实现签名
function pickCard(x: any): any {
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    } else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: ["hearts", "spades", "clubs", "diamonds"][pickedSuit], card: x % 13 };
    }
}

let myDeck = [
    { suit: "diamonds", card: 2 },
    { suit: "spades", card: 10 },
    { suit: "hearts", card: 4 }
];

let pickedCard1 = myDeck[pickCard(myDeck)];
let pickedCard2 = pickCard(15);

console.log(pickedCard1, pickedCard2);

// 6. this参数
interface Card {
    suit: string;
    card: number;
}

interface Deck {
    suits: string[];
    cards: number[];
    createCardPicker(this: Deck): () => Card;
}

let deck: Deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function(this: Deck) {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
            
            return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
        };
    }
};

let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
console.log("card: " + pickedCard.card + " of " + pickedCard.suit);

// 7. 回调函数中的this参数
interface UIElement {
    addClickListener(onclick: (this: void, e: Event) => void): void;
}

class Handler {
    info: string = "Handler info";
    
    onClickBad(this: Handler, e: Event) {
        // 这里使用this会有问题，因为this在运行时是undefined
        this.info = "clicked";
    }
    
    onClickGood = (e: Event) => {
        // 箭头函数会捕获this
        this.info = "clicked";
    }
}

// 8. 高阶函数
function createMultiplier(multiplier: number): (x: number) => number {
    return (x: number) => x * multiplier;
}

let double = createMultiplier(2);
let triple = createMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

// 9. 泛型函数
function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString");
let output2 = identity<number>(100);
// 类型推断
let output3 = identity("myString");

console.log(output1, output2, output3);

// 泛型函数类型
let myIdentity: <T>(arg: T) => T = identity;
let myIdentity2: { <T>(arg: T): T } = identity;

// 10. 约束泛型
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

// loggingIdentity(3); // 错误，number没有length属性
loggingIdentity("hello"); // 正确
loggingIdentity([1, 2, 3]); // 正确
loggingIdentity({ length: 10, value: 3 }); // 正确

// 11. 条件类型函数
type NonNullable<T> = T extends null | undefined ? never : T;

function processValue<T>(value: T): NonNullable<T> {
    if (value === null || value === undefined) {
        throw new Error("Value cannot be null or undefined");
    }
    return value as NonNullable<T>;
}

let result7 = processValue("hello");
let result8 = processValue(42);
// let result9 = processValue(null); // 运行时错误

console.log(result7, result8);

// 12. 函数作为参数
function operate(x: number, y: number, operation: (a: number, b: number) => number): number {
    return operation(x, y);
}

let sum = operate(5, 3, (a, b) => a + b);
let product = operate(5, 3, (a, b) => a * b);

console.log(sum, product);

console.log("=== 函数示例完成 ===");